package mmc.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import mmc.Settings;
import mmc.networking.Message;
import mmc.networking.Quit;
import mmc.networking.ServerWelcome;

public class RemoteClient implements Runnable{
	private Socket socket;
	private Server server;
	private boolean quit = false;
	private ObjectOutputStream out;
	private ObjectInputStream in;
	private Player player;
	private volatile boolean busy = false;
	
	public RemoteClient(Socket socket, Server server){
		this.socket = socket;
		this.server = server;
		new Thread(this).start();
	}
	
	@Override
	public void run() {
		try{
			System.out.println("client connected: "+socket);
			out = new ObjectOutputStream(socket.getOutputStream());
			post(new ServerWelcome());
			in = new ObjectInputStream(socket.getInputStream());
			
			while(!quit){
				((Message) in.readObject()).executeOnServer(this);
			}
			
			in.close();
			out.close();
			socket.close();
		}catch(Exception e){
			if(!quit){
				System.out.println("Exception in "+getClass().getCanonicalName()+"'s mainloop:");
				e.printStackTrace();
				
				System.out.println("Client "+socket+" connection reset detected, removing ...");
				breakConnection();
			}else{
				System.out.println("Connection to "+socket+" closed");
			}
		}
	}
	
	public void disconnect(){
		System.out.println("Disconnecting "+this+" ...");
		breakConnection();
		post(new Quit(Quit.QuitCause.SERVER_SHUTDOWN));
	}
	
	public void breakConnection(){
		server.clientShutdown(this);
		quit = true;
	}
	
	Object sendLock = new Object();
	public void post(Message m){
		if(!quit)
			synchronized(sendLock){
				busy = true;
				try {
					out.writeUnshared(m);
					if(Settings.CLIENT_STREAM_RESET)
						out.reset();
				} catch (IOException e) {
					System.out.println("Error while sending msg to "+socket);
					e.printStackTrace();
					
					System.out.println("Client "+socket+" connection reset detected, removing ...");
					breakConnection();
				}
				busy = false;
			}
	}
	
	public String toString(){
		return socket.toString();
	}
	
	public void setPlayer(Player p){
		player = p;
	}
	
	public Player getPlayer(){
		return player;
	}

	public Server getServer() {
		return server;
	}
	
	public boolean isBusy(){
		return busy;
	}
}
